package health

import (
	"fmt"
	"os"
	"path/filepath"

	"mcp-server/internal/config"
)

// ConfigChecker 配置文件检查器
type ConfigChecker struct {
	configPath string
}

// ConfigStatus 配置状态
type ConfigStatus struct {
	ConfigFile     ConfigFileInfo     `json:"config_file"`
	HTTPConfig     HTTPConfigInfo     `json:"http_config"`
	VectorConfig   VectorConfigInfo   `json:"vector_config"`
	DocumentConfig DocumentConfigInfo `json:"document_config"`
	Checks         []CheckResult      `json:"checks"`
	Overall        CheckStatus        `json:"overall"`
}

// ConfigFileInfo 配置文件信息
type ConfigFileInfo struct {
	Path     string `json:"path"`
	Exists   bool   `json:"exists"`
	Readable bool   `json:"readable"`
	Valid    bool   `json:"valid"`
	Size     int64  `json:"size"`
}

// HTTPConfigInfo HTTP配置信息
type HTTPConfigInfo struct {
	Port         int    `json:"port"`
	Host         string `json:"host"`
	AutoScan     bool   `json:"auto_scan"`
	ScanRange    int    `json:"scan_range"`
	CheckTimeout int    `json:"check_timeout"`
	Valid        bool   `json:"valid"`
}

// VectorConfigInfo 向量配置信息
type VectorConfigInfo struct {
	DataPath           string `json:"data_path"`
	AutoUpdateInterval int    `json:"auto_update_interval"`
	BatchSize          int    `json:"batch_size"`
	Valid              bool   `json:"valid"`
}

// DocumentConfigInfo 文档配置信息
type DocumentConfigInfo struct {
	KnowledgeBasePath string   `json:"knowledge_base_path"`
	SupportedFormats  []string `json:"supported_formats"`
	ChunkSize         int      `json:"chunk_size"`
	Valid             bool     `json:"valid"`
}

// NewConfigChecker 创建配置检查器
func NewConfigChecker(configPath string) *ConfigChecker {
	return &ConfigChecker{
		configPath: configPath,
	}
}

// CheckConfig 检查配置
func (cc *ConfigChecker) CheckConfig() *ConfigStatus {
	status := &ConfigStatus{
		Checks: []CheckResult{},
	}

	// 检查配置文件
	cc.checkConfigFile(status)

	// 如果配置文件存在且可读，则检查配置内容
	if status.ConfigFile.Exists && status.ConfigFile.Readable {
		cc.checkConfigContent(status)
	}

	// 计算总体状态
	cc.calculateOverallStatus(status)

	return status
}

// checkConfigFile 检查配置文件
func (cc *ConfigChecker) checkConfigFile(status *ConfigStatus) {
	result := CheckResult{
		Name: "配置文件检查",
	}

	// 检查文件是否存在
	info, err := os.Stat(cc.configPath)
	if os.IsNotExist(err) {
		status.ConfigFile = ConfigFileInfo{
			Path:     cc.configPath,
			Exists:   false,
			Readable: false,
			Valid:    false,
			Size:     0,
		}

		result.Status = StatusWarning
		result.Message = fmt.Sprintf("配置文件 %s 不存在，将使用默认配置", cc.configPath)
		result.Suggestion = "建议创建配置文件以自定义服务设置"
	} else if err != nil {
		status.ConfigFile = ConfigFileInfo{
			Path:     cc.configPath,
			Exists:   true,
			Readable: false,
			Valid:    false,
			Size:     0,
		}

		result.Status = StatusFail
		result.Message = fmt.Sprintf("无法访问配置文件: %v", err)
		result.Suggestion = "请检查文件权限"
	} else {
		// 检查文件是否可读
		readable := cc.isFileReadable(cc.configPath)

		status.ConfigFile = ConfigFileInfo{
			Path:     cc.configPath,
			Exists:   true,
			Readable: readable,
			Valid:    false, // 将在内容检查中确定
			Size:     info.Size(),
		}

		if readable {
			result.Status = StatusPass
			result.Message = fmt.Sprintf("配置文件 %s 存在且可读 (大小: %d 字节)", cc.configPath, info.Size())
		} else {
			result.Status = StatusFail
			result.Message = fmt.Sprintf("配置文件 %s 存在但不可读", cc.configPath)
			result.Suggestion = "请检查文件权限"
		}
	}

	status.Checks = append(status.Checks, result)
}

// checkConfigContent 检查配置内容
func (cc *ConfigChecker) checkConfigContent(status *ConfigStatus) {
	// 尝试加载配置
	configManager := config.NewConfigManager(cc.configPath)
	if err := configManager.LoadConfig(); err != nil {
		result := CheckResult{
			Name:       "配置内容检查",
			Status:     StatusFail,
			Message:    fmt.Sprintf("配置文件格式错误: %v", err),
			Suggestion: "请检查YAML格式是否正确",
		}
		status.Checks = append(status.Checks, result)
		return
	}

	status.ConfigFile.Valid = true

	// 检查HTTP配置
	cc.checkHTTPConfig(status, configManager)

	// 检查向量配置
	cc.checkVectorConfig(status, configManager)

	// 检查文档配置
	cc.checkDocumentConfig(status, configManager)
}

// checkHTTPConfig 检查HTTP配置
func (cc *ConfigChecker) checkHTTPConfig(status *ConfigStatus, configManager *config.ConfigManager) {
	result := CheckResult{
		Name: "HTTP配置检查",
	}

	httpConfig := configManager.GetHTTPConfig()
	if httpConfig == nil {
		result.Status = StatusFail
		result.Message = "HTTP配置缺失"
		result.Suggestion = "请在配置文件中添加http配置节"
		status.Checks = append(status.Checks, result)
		return
	}

	status.HTTPConfig = HTTPConfigInfo{
		Port:         httpConfig.Port,
		Host:         httpConfig.Host,
		AutoScan:     httpConfig.AutoScan,
		ScanRange:    httpConfig.ScanRange,
		CheckTimeout: httpConfig.CheckTimeout,
		Valid:        true,
	}

	// 验证端口范围
	if httpConfig.Port < 1 || httpConfig.Port > 65535 {
		result.Status = StatusFail
		result.Message = fmt.Sprintf("HTTP端口 %d 超出有效范围 (1-65535)", httpConfig.Port)
		result.Suggestion = "请设置有效的端口号"
		status.HTTPConfig.Valid = false
	} else if httpConfig.Port < 1024 {
		result.Status = StatusWarning
		result.Message = fmt.Sprintf("HTTP端口 %d 需要管理员权限", httpConfig.Port)
		result.Suggestion = "建议使用1024以上的端口或以管理员身份运行"
	} else {
		result.Status = StatusPass
		result.Message = fmt.Sprintf("HTTP配置有效 (端口: %d, 主机: %s)", httpConfig.Port, httpConfig.Host)
	}

	status.Checks = append(status.Checks, result)
}

// checkVectorConfig 检查向量配置
func (cc *ConfigChecker) checkVectorConfig(status *ConfigStatus, configManager *config.ConfigManager) {
	result := CheckResult{
		Name: "向量数据库配置检查",
	}

	vectorConfig := configManager.GetVectorConfig()
	if vectorConfig == nil {
		result.Status = StatusWarning
		result.Message = "向量数据库配置缺失，将使用默认配置"
		result.Suggestion = "建议在配置文件中添加vector配置节"
		status.Checks = append(status.Checks, result)
		return
	}

	status.VectorConfig = VectorConfigInfo{
		DataPath:           vectorConfig.DataPath,
		AutoUpdateInterval: vectorConfig.AutoUpdateInterval,
		BatchSize:          vectorConfig.BatchSize,
		Valid:              true,
	}

	// 检查数据路径
	if vectorConfig.DataPath != "" {
		if err := cc.validateDataPath(vectorConfig.DataPath); err != nil {
			result.Status = StatusWarning
			result.Message = fmt.Sprintf("向量数据路径问题: %v", err)
			result.Suggestion = "请确保数据路径可写或留空使用默认路径"
			status.VectorConfig.Valid = false
		} else {
			result.Status = StatusPass
			result.Message = fmt.Sprintf("向量数据库配置有效 (数据路径: %s)", vectorConfig.DataPath)
		}
	} else {
		result.Status = StatusPass
		result.Message = "向量数据库配置有效 (使用默认数据路径)"
	}

	status.Checks = append(status.Checks, result)
}

// checkDocumentConfig 检查文档配置
func (cc *ConfigChecker) checkDocumentConfig(status *ConfigStatus, configManager *config.ConfigManager) {
	result := CheckResult{
		Name: "文档处理配置检查",
	}

	docConfig := configManager.GetDocumentConfig()
	if docConfig == nil {
		result.Status = StatusWarning
		result.Message = "文档处理配置缺失，将使用默认配置"
		result.Suggestion = "建议在配置文件中添加document配置节"
		status.Checks = append(status.Checks, result)
		return
	}

	status.DocumentConfig = DocumentConfigInfo{
		KnowledgeBasePath: docConfig.KnowledgeBasePath,
		SupportedFormats:  docConfig.SupportedFormats,
		ChunkSize:         docConfig.ChunkSize,
		Valid:             true,
	}

	// 检查知识库路径
	if docConfig.KnowledgeBasePath != "" {
		if err := cc.validateKnowledgeBasePath(docConfig.KnowledgeBasePath); err != nil {
			result.Status = StatusWarning
			result.Message = fmt.Sprintf("知识库路径问题: %v", err)
			result.Suggestion = "请确保知识库路径存在且可读"
			status.DocumentConfig.Valid = false
		} else {
			result.Status = StatusPass
			result.Message = fmt.Sprintf("文档处理配置有效 (知识库路径: %s)", docConfig.KnowledgeBasePath)
		}
	} else {
		result.Status = StatusPass
		result.Message = "文档处理配置有效 (使用默认知识库路径)"
	}

	status.Checks = append(status.Checks, result)
}

// calculateOverallStatus 计算总体状态
func (cc *ConfigChecker) calculateOverallStatus(status *ConfigStatus) {
	hasFailure := false
	hasWarning := false

	for _, check := range status.Checks {
		switch check.Status {
		case StatusFail:
			hasFailure = true
		case StatusWarning:
			hasWarning = true
		}
	}

	if hasFailure {
		status.Overall = StatusFail
	} else if hasWarning {
		status.Overall = StatusWarning
	} else {
		status.Overall = StatusPass
	}
}

// 辅助函数

// isFileReadable 检查文件是否可读
func (cc *ConfigChecker) isFileReadable(path string) bool {
	file, err := os.Open(path)
	if err != nil {
		return false
	}
	defer file.Close()

	// 尝试读取一个字节
	buffer := make([]byte, 1)
	_, err = file.Read(buffer)
	return err == nil || err.Error() == "EOF"
}

// validateDataPath 验证数据路径
func (cc *ConfigChecker) validateDataPath(path string) error {
	// 检查路径是否存在
	if _, err := os.Stat(path); os.IsNotExist(err) {
		// 尝试创建目录
		if err := os.MkdirAll(path, 0755); err != nil {
			return fmt.Errorf("无法创建数据目录: %v", err)
		}
	}

	// 检查是否可写
	testFile := filepath.Join(path, ".write_test")
	if err := os.WriteFile(testFile, []byte("test"), 0644); err != nil {
		return fmt.Errorf("数据目录不可写: %v", err)
	}

	// 清理测试文件
	os.Remove(testFile)
	return nil
}

// validateKnowledgeBasePath 验证知识库路径
func (cc *ConfigChecker) validateKnowledgeBasePath(path string) error {
	// 检查路径是否存在
	info, err := os.Stat(path)
	if os.IsNotExist(err) {
		return fmt.Errorf("知识库路径不存在: %s", path)
	}
	if err != nil {
		return fmt.Errorf("无法访问知识库路径: %v", err)
	}

	// 检查是否为目录
	if !info.IsDir() {
		return fmt.Errorf("知识库路径不是目录: %s", path)
	}

	// 检查是否可读
	entries, err := os.ReadDir(path)
	if err != nil {
		return fmt.Errorf("知识库目录不可读: %v", err)
	}

	// 检查是否包含支持的文件
	hasValidFiles := false
	supportedExts := []string{".md", ".txt", ".pdf", ".docx"}

	for _, entry := range entries {
		if entry.IsDir() {
			continue
		}

		ext := filepath.Ext(entry.Name())
		for _, supportedExt := range supportedExts {
			if ext == supportedExt {
				hasValidFiles = true
				break
			}
		}

		if hasValidFiles {
			break
		}
	}

	if !hasValidFiles {
		return fmt.Errorf("知识库目录中未找到支持的文件格式 (%v)", supportedExts)
	}

	return nil
}
